home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1986, 1992, 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /**************************************************************************
- * Streams driver for the Comtrol Hostess 550 serial port controller
- *
- * This driver controls up to 4 Controller, each with 8 independent
- * ports to use. Each port on a controller is capable of working as
- * a serial port, Modem or Flow control and this module must determine
- * how each port is being used. For this reason, we use the device's
- * Minor Number to determine:
- * - Controller number
- * - Port Number within that controller
- * - Whether the port is being used as Modem
- * or Flow Control.
- *
- * There are 96 Minor device numbers, each assigned to a unique
- * /dev/ttyxxx file (32 ports, each can be set as serial port, Modem
- * or Flow control, hence 32 x 3 = 96 minor device number needed).
- *
- * These Minor numbers are as follow:
- *
- * Minor number Controller Description
- * ------------ ---------- -----------
- * 0 - 7 0 Serial Ports
- * 8 - 15 1 Serial Ports
- * 16 - 23 2 Serial Ports
- * 24 - 31 3 Serial Ports
- *
- * 32 - 39 0 Modem Ports
- * 40 - 47 1 Modem Ports
- * 48 - 55 2 Modem Ports
- * 56 - 63 3 Modem Ports
- *
- * 64 - 71 0 Flow Control Ports
- * 72 - 79 1 Flow Control Ports
- * 80 - 87 2 Flow Control Ports
- * 88 - 95 3 Flow Control Ports
- *
- *
- * $Revision: 1.00 $
- ****************************************************************************
- */
-
- #include "sys/cmn_err.h"
- #include "sys/debug.h"
- #include "sys/errno.h"
- #include "sys/file.h"
- #include "sys/param.h"
- #include "sys/signal.h"
- #include "sys/stream.h"
- #include "sys/strids.h"
- #include "sys/strmp.h"
- #include "sys/stropts.h"
- #include "sys/stty_ld.h"
- #include "sys/sysinfo.h"
- #include "sys/sysmacros.h"
- #include "sys/systm.h"
- #include "sys/termio.h"
- #include "sys/types.h"
- #include "sys/cpu.h"
- #include "sys/user.h"
- #include "sys/sema.h"
- #include "sys/ddi.h"
- #include "sys/edt.h"
- #include "sys/pio.h"
- #include "sys/eisa.h"
- #include "sys/cred.h"
-
- #include "./h550.h"
-
- #define STRID_h550 9037 /***** should be moved to strids.h later *****/
-
- /* for debugging */
- #ifdef DEBUG
- static h550debug = 0;
- #endif
-
- /* 'extern' stuff ... */
- extern int kdebugbreak;
- extern struct stty_ld def_stty_ld;
- extern int duart_rsrv_duration; /* send input this often */
-
- int chars_rcvd;
- int chars_xmt;
-
- /* default cflags */
- #define DEF_CFLAG ((ushort_t)(CREAD | def_stty_ld.st_cflag))
- #define CNTRL_A '\001'
-
- /* Misc. defines .. */
- #define MIN_RMSG_LEN 4 /* minimum buffer size */
- #define MAX_RMSG_LEN 2048 /* largest msg allowed */
- #define XOFF_RMSG_LEN 256 /* send XOFF here */
- #define MAX_RBUF_LEN 1024
- #define MAX_RSRV_CNT 3 /* continue input timer this long */
-
- #define INB(x) (*(volatile uchar_t *)(x))
- #define OUTB(x,y) (*(volatile uchar_t *)(x) = (y))
-
- #define EISA_NUM_SLOTS 4
- #define NUMMINOR 8 /* must be (2**n) */
- #define PORT(dev) ((dev) & (NUMMINOR - 1))
- #define MODEM(dev) ((dev) & (NUMMINOR * 4))
- #define FLOW_MODEM(dev) ((dev) & (NUMMINOR * 8))
-
- #define SEND_XON 1
- #define SEND_XOFF 0
- #define IGNORE_IXOFF 1
-
- /* all the data in a given Device Minor Number */
- typedef struct minorNumInfo {
- short m_ctl; /* controller number */
- short m_port; /* port in the controller */
- short m_modem; /* 1 = operating as Modem */
- short m_flow; /* 1 = operating as Flow Control */
- } minorNumInfo_t;
-
-
- /*********************************************************************
- * Port's static data *
- *********************************************************************
- * We keep track of these data for each port on a controller.
- * Note that there might be 4 controller, each having 8 ports.
- * (total of 32 ports can be available).
- */
- typedef struct h550port {
- /* hardware address */
- uchar_t dp_ctl; /* Controller's number */
- uchar_t dp_index; /* port number */
- caddr_t port_addr; /* port's address */
-
- int xmitlev; /* Transmit level */
- int open; /* Number of open FIFO positions */
-
- uchar_t dp_rsrv_cnt; /* input timer count */
- int dp_rsrv_duration; /* input timer */
-
- uint_t dp_state; /* current state */
-
- struct termio dp_termio;
- queue_t *dp_rq, *dp_wq; /* our queues */
- mblk_t *dp_rmsg, *dp_rmsge; /* current input message, head/tail */
- int dp_rmsg_len; /* current input message length */
- int dp_rbsize; /* recent input message length */
- mblk_t *dp_rbp; /* current input buffer */
- mblk_t *dp_wbp; /* current output buffer */
-
- int dp_tid; /* (recent) output delay timer ID */
-
- int dp_fe, dp_over; /* framing/overrun errors counts */
- int dp_allocb_fail; /* losses due to allocb() failures */
- } h550port_t;
-
- /* dp_termio various fields... */
- #define dp_iflag dp_termio.c_iflag /* use some of the bits (see below) */
- #define dp_cflag dp_termio.c_cflag /* use all of the standard bits */
- #define dp_line dp_termio.c_line /* line discipline */
- #define dp_cc dp_termio.c_cc /* control characters */
-
- /* bits in dp_state */
- #define DP_ISOPEN 0x00000001 /* device is open */
- #define DP_WOPEN 0x00000002 /* waiting for carrier */
- #define DP_DCD 0x00000004 /* we have carrier */
- #define DP_TIMEOUT 0x00000008 /* delaying */
- #define DP_BREAK 0x00000010 /* breaking */
- #define DP_BREAK_QUIET 0x00000020 /* finishing break */
- #define DP_TXSTOP 0x00000040 /* output stopped by received XOFF */
- #define DP_LIT 0x00000080 /* have seen literal character */
- #define DP_BLOCK 0x00000100 /* XOFF sent because input full */
- #define DP_TX_TXON 0x00000200 /* need to send XON */
- #define DP_TX_TXOFF 0x00000400 /* need to send XOFF */
- #define DP_SE_PENDING 0x00000800 /* buffer alloc event pending */
-
- #define DP_EXTCLK 0x10000000 /* external clock mode */
- #define DP_MANCTRL 0x20000000 /* Manual control of RTS & DTR */
- #define DP_FLOW 0x40000000 /* do hardware flow control */
- #define DP_MODEM 0x80000000 /* modem device */
-
- #define DP_BREAK_ON 0x00010000 /* receiving break */
- #define DP_CTS 0x00020000 /* CTS on */
-
- /*************************************************************************
- * Controllers Data/Status Array *
- *************************************************************************
- * This Array has an entry for each Controller we support.
- * All Driver routines deal with one of these entries. The
- * entry itself keeps data/status for the Controller's base address,
- * IRQ assigned, and contains Port info/data for each of 8 ports
- * of the controller.
- */
- typedef struct edrvinfo {
- caddr_t e_addr[NBASE];
- int e_dmachan;
- int e_irq;
- int e_numports;
- int e_intmask;
- h550port_t e_ports[MAX_PORTS];
- } edrvinfo_t;
-
- static edrvinfo_t einfo[EISA_NUM_SLOTS]; /* Controller Array */
-
-
- /*
- * Driver Entry routines in this file
- */
- struct cred;
- static void h550_rsrv(queue_t *);
- static int h550_open(queue_t *, dev_t *, int, int, struct cred *);
- static int h550_close(queue_t *, int, struct cred *);
- static void h550_poll();
- static int h550_wput(queue_t *, mblk_t *);
-
- static void h550_con(h550port_t *);
- static void h550_coff(h550port_t *);
- static void h550_flushw(h550port_t *);
- static void h550_flushr(struct h550port *);
- static mblk_t *h550_getbp(h550port_t *, uint_t);
- static void h550_rx(h550port_t *);
- static void h550_tx(h550port_t *, int);
-
-
- /*
- ****************************************************************
- * Unix STREAM device driver required structures and data. *
- ****************************************************************
- * The required structure are: *
- * - Module Info *
- * - qinit for Read and Write (In and Out) queues *
- * - streamtab structure to point to all above *
- * Refer to your Unix Device Driver manual for more info *
- ****************************************************************
- */
-
- /* Module Info structure */
- static struct module_info h550m_info =
- {
- STRID_h550, /* module ID */
- "h550", /* module name */
- 0, /* minimum packet size */
- INFPSZ, /* maximum packet size--infinite */
- 128, /* hi-water mark */
- 16, /* lo-water mark */
- };
-
- /* 'qinit' for Input queue (Read queue) */
- static struct qinit h550rinit = {
- NULL, (int (*)())h550_rsrv, h550_open, h550_close, NULL, &h550m_info, NULL
- };
-
- /* 'qinit' for Output queue (Write queue) */
- static struct qinit h550winit = {
- h550_wput, NULL, NULL, NULL, NULL, &h550m_info, NULL
- };
-
- /* 'streamtab' for the drive (put all above together) */
- struct streamtab h550info = {
- &h550rinit, &h550winit, NULL, NULL
- };
-
- /*
- ****************************************************
- * EISA bus interface data/variables *
- ****************************************************
- */
-
- /*
- * EISA interrupt mask for each controller. Each bit
- * represents an Interrupt number requested. We use
- * the following Interrupt numbers (IRQs):
- * Ctrl No IRQ no Mask
- * ------- ------ ------
- * 0 3 0x0008
- * 1 4 0x0010
- * 2 5 0x0020
- * 3 10 0x0400
- *
- * Refer to: User's guide to Comtrol Hostess 550
- * IRIX Dev.Driver programing Guide (EISA Device Driver)
- */
-
- static int IRQ_MASK[] = {0x0008, 0x0010, 0x0020, 0x0400};
-
- /*
- * Specifying Interrupt Handling routines for each IRQ specified
- * above (see IRQ_MASKs). See edtinit routine for EISA bus for more info.
- */
-
- /* used in order to pass controller number to the routine */
- typedef void (* intentry_t)();
- void h550_poll_0(){h550_poll(0);}
- void h550_poll_1(){h550_poll(1);}
- void h550_poll_2(){h550_poll(2);}
- void h550_poll_3(){h550_poll(3);}
-
- /* interrupt handling table (one for each controller) */
- intentry_t intentrypnt[N_ADAPTERS] = {
- h550_poll_0,
- h550_poll_1,
- h550_poll_2,
- h550_poll_3,
- };
-
- int h550devflag = 0;
-
- static fifo_size = 16; /* on chip transmit FIFO size */
-
- static void ShowPortInfo(ushort_t, h550port_t *);
- static void getMinorInfo(minor_t, minorNumInfo_t *);
-
- static void comtrol_h550_break(h550port_t *, int);
- static void comtrol_h550_config(h550port_t *, ushort_t, struct termio *);
- static int comtrol_h550_getchar(h550port_t *);
- static void comtrol_h550_iflow(h550port_t *, int, int);
- static void comtrol_h550_putchar(h550port_t *, uchar_t);
- static int comtrol_h550_start_rx(h550port_t *);
- static void comtrol_h550_start_tx(h550port_t *);
- static void comtrol_h550_stop_rx(h550port_t *, int);
- static void comtrol_h550_stop_tx(h550port_t *);
- static int comtrol_h550_txrdy(h550port_t *);
-
- static int h550_baudtbl[] = {
- 0, /* B0 */
- 2304, /* 50 */
- 1536, /* 75 */
- 1047, /* 110 */
- 857, /* 134 */
- 768, /* 150 */
- 0, /* 200 */
- 384, /* 300 */
- 192, /* 600 */
- 96, /* 1200 */
- 64, /* 1800 */
- 48, /* 2400 */
- 24, /* 4800 */
- 12, /* 9600 */
- 6, /* exta - 19200 */
- 3 /* extb - 38400 */
- };
-
-
-
- /**************************************************************************
- * h 5 5 0 _ r c l r *
- **************************************************************************
- *
- * Name: h550_rclr
- *
- * Description:
- * Gobble any waiting input for a port.
- * Should only be called when safe from interrupts.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_rclr( h550port_t *dp )
- {
- int c;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"rclr: Read clear routine");
- #endif /* DEBUG2 */
-
- while ((c = comtrol_h550_getchar(dp)) != -1) {
- }
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ z a p *
- **************************************************************************
- *
- * Name: h550_zap
- *
- * Description:
- * Shut down a port.
- * Should only be called when safe from interrupts.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- h550_zap( h550port_t *dp, int hup )
- {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Zap routine");
- #endif /* DEBUG2 */
-
- h550_flushw(dp); /* forget pending output */
-
- comtrol_h550_stop_rx(dp, hup);
- comtrol_h550_stop_tx(dp);
-
- h550_rclr(dp);
- }
-
- /**************************************************************************
- * h 5 5 0 _ d e l a y *
- **************************************************************************
- *
- * Name: h550_delay
- *
- * Description:
- * Finish a delay for a port.
- *
- * Returns:
- *
- **************************************************************************
- */
-
-
- static void
- h550_delay( h550port_t *dp )
- {
- int s;
-
- s = LOCK_PORT(dp);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Delay routine");
- #endif /* DEBUG2 */
-
- if ((dp->dp_state & (DP_BREAK | DP_BREAK_QUIET)) != DP_BREAK) {
-
- dp->dp_state &= ~(DP_TIMEOUT | DP_BREAK | DP_BREAK_QUIET);
- comtrol_h550_start_tx(dp); /* resume output */
-
- }
- else { /* unless need to quiet break */
- comtrol_h550_break(dp, 0);
- dp->dp_state |= DP_BREAK_QUIET;
- dp->dp_tid = STREAMS_TIMEOUT(h550_delay, (caddr_t)dp, HZ/20);
- }
-
- UNLOCK_PORT(dp, s);
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ r s r v _ t i m e r *
- **************************************************************************
- *
- * Name: h550_rsrv_timer
- *
- * Description:
- * Heartbeat to send input up stream.
- * This is used to reduced the large cost of trying to
- * send each input byte upstream by itself.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_rsrv_timer( h550port_t *dp )
- {
- int s;
-
- s = LOCK_PORT(dp);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Read service timer routine");
- #endif /* DEBUG2 */
-
- if (--dp->dp_rsrv_cnt)
- (void)STREAMS_TIMEOUT(h550_rsrv_timer, (caddr_t)dp,
- dp->dp_rsrv_duration);
-
- if (dp->dp_state & DP_ISOPEN && canenable(dp->dp_rq))
- qenable(dp->dp_rq);
-
- UNLOCK_PORT(dp, s);
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ f l u s h w *
- **************************************************************************
- *
- * Name: h550_flushw
- *
- * Description:
- * Flush output for a port.
- * Should only be called when safe from Interrupts.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_flushw( h550port_t *dp )
- {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Flush write routine");
- #endif /* DEBUG2 */
-
- if ((dp->dp_state & (DP_TIMEOUT | DP_BREAK | DP_BREAK_QUIET))
- == DP_TIMEOUT)
- {
- untimeout(dp->dp_tid); /* forget stray timeout */
- dp->dp_state &= ~DP_TIMEOUT;
- }
-
- freemsg(dp->dp_wbp);
- dp->dp_wbp = NULL;
- }
-
- /**************************************************************************
- * h 5 5 0 _ f l u s h r *
- **************************************************************************
- *
- * Name: h550_flushr
- *
- * Description:
- * Flush input for a port.
- * Should only be called when safe from Interrupts.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_flushr( h550port_t *dp )
- {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Flush read routine");
- #endif /* DEBUG2 */
-
- freemsg(dp->dp_rmsg);
- dp->dp_rmsg = NULL;
- dp->dp_rmsg_len = 0;
- freemsg(dp->dp_rbp);
- dp->dp_rbp = NULL;
-
- qenable(dp->dp_rq); /* turn input back on */
- }
-
- /**************************************************************************
- * h 5 5 0 _ save *
- **************************************************************************
- *
- * Name: h550_save
- *
- * Description:
- * Save a message on our write queue and start
- * the output interrupt if necessary.
- *
- * Returns:
- *
- **************************************************************************
- */
- static int
- h550_save(h550port_t *dp,
- queue_t *wq,
- mblk_t *bp )
- {
- volatile caddr_t addr;
- uchar_t b;
-
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Save message routine");
- #endif /* DEBUG2 */
-
- putq(wq, bp); /* save the message */
-
- addr = dp->port_addr;
- b = INB(addr+IER);
-
- if ( !(b & ETBEI) )
- comtrol_h550_start_tx(dp); /* start TX only if we must */
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ tcgeta *
- **************************************************************************
- *
- * Name: h550_tcgeta
- *
- * Description:
- * Get current tty parameters.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- void
- h550_tcgeta( queue_t *wq,
- mblk_t *bp,
- struct termio *p )
- {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Get tty parameters routine");
- #endif /* DEBUG2 */
-
- *STERMIO(bp) = *p;
-
- bp->b_datap->db_type = M_IOCACK;
- qreply(wq, bp);
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ tcset *
- **************************************************************************
- *
- * Name: h550_tcset
- *
- * Description:
- * Set tty parameters.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- h550_tcset( h550port_t *dp,
- mblk_t *bp )
-
- {
- ushort_t cflag;
- struct iocblk *iocp;
- struct termio *tp;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Set tty parameters routine");
- #endif /* DEBUG2 */
-
- iocp = (struct iocblk *)bp->b_rptr;
- tp = STERMIO(bp);
-
- cflag = tp->c_cflag;
-
- if (dp->dp_state & DP_MODEM) {
- /*
- * On modem ports, only super-user can change CLOCAL.
- * Otherwise, fail to do so silently for historic reasons.
- */
- if (((dp->dp_cflag & CLOCAL) ^ (cflag & CLOCAL)) && !suser()) {
- u.u_error = 0;
- cflag &= ~CLOCAL;
- cflag |= dp->dp_cflag & CLOCAL;
- }
-
- }
-
- comtrol_h550_config(dp, cflag, tp);
-
- tp->c_cflag = dp->dp_cflag; /* tell line discipline the results */
-
- iocp->ioc_count = 0;
- bp->b_datap->db_type = M_IOCACK;
- }
-
-
- /**************************************************************************
- * h550_i_ioctl *
- **************************************************************************
- *
- * Name: h550_i_ioctl
- *
- * Description:
- * Interrupt - Process an IOCTL. This function processes
- * those IOCTLs that must be done by the output interrupt.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- h550_i_ioctl( h550port_t *dp,
- mblk_t *bp )
- {
- struct iocblk *iocp;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Interrupt process routine");
- #endif /* DEBUG2 */
-
- iocp = (struct iocblk *)bp->b_rptr;
-
- switch (iocp->ioc_cmd) {
-
- case TCSBRK:
-
- if (!*(int *)bp->b_cont->b_rptr) {
-
- dp->dp_state |= DP_TIMEOUT | DP_BREAK;
- comtrol_h550_break(dp, 1);
- dp->dp_tid = STREAMS_TIMEOUT(h550_delay, (caddr_t)dp, HZ/4);
- }
-
- iocp->ioc_count = 0;
- bp->b_datap->db_type = M_IOCACK;
- break;
-
- case TCSETAF:
-
- h550_tcset(dp, bp);
- h550_flushr(dp);
- (void)putctl1(dp->dp_rq->q_next, M_FLUSH, FLUSHR);
- break;
-
- case TCSETA:
- case TCSETAW:
-
- h550_tcset(dp, bp);
- break;
-
- case TCGETA:
-
- h550_tcgeta(dp->dp_wq, bp, &dp->dp_termio);
- return;
-
- default:
-
- ASSERT(0);
- }
-
- putnext(dp->dp_rq, bp);
- }
-
-
- #ifdef DEBUG2
-
-
- /**************************************************************************
- * d u m p _ d p *
- **************************************************************************
- *
- * Name: dump_dp
- *
- * Description:
- * Prints out a port's info
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- dump_dp( h550port_t *dp )
- {
- qprintf("Ctl %d, Port %d\n", dp->dp_ctl, dp->dp_index);
- qprintf("State: ");
- if (dp->dp_state & DP_ISOPEN)
- qprintf("ISOPEN ");
- if (dp->dp_state & DP_WOPEN)
- qprintf("WOPEN ");
- if (dp->dp_state & DP_DCD)
- qprintf("DCD ");
- if (dp->dp_state & DP_TIMEOUT)
- qprintf("TIMEOUT ");
- if (dp->dp_state & DP_BREAK)
- qprintf("BREAK ");
- if (dp->dp_state & DP_BREAK_QUIET)
- qprintf("BREAK_QUIET ");
- if (dp->dp_state & DP_TXSTOP)
- qprintf("TXSTOP ");
- if (dp->dp_state & DP_LIT)
- qprintf("LIT ");
- if (dp->dp_state & DP_BLOCK)
- qprintf("BLOCK ");
- if (dp->dp_state & DP_TX_TXON)
- qprintf("TX_TXON ");
- if (dp->dp_state & DP_TX_TXOFF)
- qprintf("TX_TXOFF ");
- if (dp->dp_state & DP_SE_PENDING)
- qprintf("SE_PENDING ");
- if (dp->dp_state & DP_EXTCLK)
- qprintf("EXTCLK ");
- if (dp->dp_state & DP_FLOW)
- qprintf("FLOW ");
- if (dp->dp_state & DP_MODEM)
- qprintf("MODEM ");
- if (dp->dp_state & DP_BREAK_ON)
- qprintf("BREAK_ON ");
- if (dp->dp_state & DP_CTS)
- qprintf("CTS ");
- qprintf("\n");
-
- qprintf("Framing errors: %d, Overruns: %d, Alloc failed: %d\n",
- dp->dp_fe, dp->dp_over, dp->dp_allocb_fail);
- }
- #endif
-
- /*********************************************************************
- * h 5 5 0 _ g e t p o r t s
- *********************************************************************
- *
- * Name: h550_getports
- *
- * Description:
- *
- * Returns the number of valid ports on a controller.
- * The base address of the port #0 is given. This routine
- * Outputs/Inputs from each port and if expected value is read
- * then will assume the port is ok.
- *
- * Returns:
- * Number of working ports.
- **********************************************************************
- */
-
- static int
- h550_getports( caddr_t baseaddr,
- int max_ports )
- {
- register int i, ok_ports;
- caddr_t addr;
-
- ok_ports = 0;
- addr = baseaddr;
-
- for ( i = 0; i < max_ports; i++ ) {
-
- OUTB(addr+IER,0x00);
- OUTB(addr+LCR,0x80);
- OUTB(addr+DLM,0xff);
- OUTB(addr+LCR,0x00);
-
- if (INB(addr+IER) == 0) {
- ok_ports++;
- addr += 8;
- }
- else break;
- }
-
-
- #ifdef DEBUG2
- cmn_err(CE_DEBUG2,"getports: Found %d ports\n", ok_ports);
- #endif /* DEBUG2 */
-
- return(ok_ports);
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ s e t a d d r *
- **************************************************************************
- *
- * Name: h550_setaddr
- *
- * Description:
- * This routine sets the addresses of all ports for
- * a given Controller.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static
- h550_setaddr( caddr_t baseaddr,
- int ports,
- int ctrl )
- {
- register int i;
- caddr_t addr;
- h550port_t *dp;
-
- dp = &einfo[ctrl].e_ports[0];
- addr = baseaddr;
-
- cmn_err(CE_NOTE,"Baseaddr = 0x%x\n", baseaddr);
- cmn_err(CE_NOTE,"Ctrl = %d, Ports = %d\n", ctrl, ports);
-
- for (i=0; i < ports; i++) {
- dp[i].port_addr = addr;
- cmn_err(CE_NOTE, "Ctrl = 0x%x, port = %d, port_addr = 0x%x\n",
- ctrl, i, addr);
- addr += 8;
- }
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ s e t 5 5 0 *
- **************************************************************************
- *
- * Name: h550_set550
- *
- * Description:
- *
- * Initilize all ports on a given controller.
- *
- * Returns: Number of ports initialized.
- *
- **************************************************************************
- */
-
- static int
- h550_set550( int dev,
- int ports )
- {
- register int i;
- caddr_t addr;
- int retval, h550_fcr;
- uchar_t iir;
-
- retval = 0;
-
- for (i = 0; i < ports; i++) {
-
- addr = einfo[dev].e_ports[i].port_addr;
- OUTB(addr+FCR,0x01); /* enable FIFOs */
-
- iir = INB(addr+IIR);
- if ( (iir & 0xc0) == 0xc0 ) {
-
- switch ( TRIGGER ) {
- case 4:
- h550_fcr = 0x41;
- break;
- case 8:
- h550_fcr = 0x81;
- break;
- case 14:
- h550_fcr = 0xc1;
- break;
- default:
- h550_fcr = 0x01;
- break;
- }
-
- OUTB(addr+FCR,h550_fcr);
- ++retval;
- }
- }
-
- return(retval);
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ e d t i n i t *
- **************************************************************************
- *
- * Name: h550_edtinit
- *
- * Description:
- *
- * Called once for each Controller to initialize the
- * controller. This initialization includes mapping
- * board's IO address space, setting up Interrupt number
- * and Interrup handler and initializing all the ports
- * addresses for the controller.
- *
- * Returns:
- *
- **************************************************************************
- */
- void
- h550edtinit( edt_t *e )
- {
- int iospace, eirq, ctlr_num;
- edrvinfo_t *einf;
- piomap_t *pmap;
-
- h550port_t *dp;
- char *env;
- register int ports, i;
- caddr_t addr;
-
-
- /*
- * get the controller and the controller's port array
- */
- ctlr_num = e->e_ctlr;
- einf = &einfo[ctlr_num];
- dp = &einf->e_ports[0];
-
- #ifdef DEBUG2
- cmn_err(CE_DEBUG2,"Controller number is: %d\n", ctlr_num);
- #endif /*DEBUG2 */
-
- /*
- * Initialize all port variables for this controller.
- */
- for ( i = 0; i < MAX_PORTS; i++ ) {
- dp[i].dp_index = i;
- dp[i].dp_ctl = ctlr_num;
- dp[i].port_addr = 0;
- dp[i].xmitlev = 16; /* default */
- dp[i].open = 16;
- dp[i].dp_state = 0;
- }
-
- /*
- * Map EISA address spaces for this controller
- * (Note that there are 3 address: 1 for IO, 2 for Memory
- * see EISA Driver requirements for more info).
- */
- for (iospace = 0; iospace < NBASE; iospace++) {
- if (!e->e_space[iospace].ios_iopaddr) /* no more addresses */
- continue;
-
- pmap = pio_mapalloc(e->e_bus_type, e->e_adap,
- &e->e_space[iospace], PIOMAP_FIXED, "h550");
-
- einf->e_addr[iospace] = pio_mapaddr(pmap,
- e->e_space[iospace].ios_iopaddr);
- }
-
- /* probe for device */
- if (badaddr(einf->e_addr[0], 1)) {
- cmn_err(CE_WARN, "h550: ctlr %d not installed",
- ctlr_num);
- return;
- }
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Base address is: %x\n", einf->e_addr[0]);
- #endif /* DEBUG2 */
-
- /*
- * Allocate Interrupt Vector for this Controller.
- */
- eirq = eisa_ivec_alloc(e->e_adap, IRQ_MASK[ctlr_num],
- EISA_EDGE_IRQ);
- if (eirq < 0) {
- cmn_err(CE_WARN, "h550: ctlr %d could not allocate IRQ",
- ctlr_num);
- return;
- }
-
- einf->e_irq = eirq;
-
- /*
- * Set the allocated Interrup Vector and assign proper
- * Interrupt Handler to it (see EISA Driver requirement).
- */
- eisa_ivec_set(e->e_adap, eirq, intentrypnt[ctlr_num], ctlr_num);
-
- /*
- * Get the actual number of working ports on this controller
- * and calculate the base address of each Port's registers.
- */
- addr = einf->e_addr[0];
- if ( (ports = h550_getports(addr, MAX_PORTS) ) > 0) {
-
- h550_setaddr(addr, ports, ctlr_num);
-
- /* set the Interrupt Mask (Register 7) */
- if (h550_set550(ctlr_num, ports) == ports) {
- einf->e_numports = ports;
-
- for (i = 0; i < ports; i++)
- einf->e_intmask = (einf->e_intmask << 1) + 1;
-
- OUTB(addr+MASK,einf->e_intmask);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"POLL register: 0x%x", INB(addr+POLL));
- #endif
-
- if(showconfig)
- cmn_err(CE_NOTE,
- "HOSTESS 550 Controller found at %xH,"
- "IRQ%d, %d ports", addr, eirq, ports );
- }
-
- /*
- * h550_set550 did not return the number of ports expected
- * so set all Port addresses to zero.
- */
- else {
- for (i=0;i<ports;i++)
- dp[i].port_addr = 0;
- if(showconfig)
- cmn_err(CE_NOTE,
- "HOSTESS 550 Controller not found at %xH,"
- "IRQ%d, %d ports", dp[0].port_addr,
- eirq,ports);
- }
- }
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ o p e n *
- **************************************************************************
- *
- * Name: h550_open
- *
- * Description:
- * Opens a UART port as a stream.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static int
- h550_open( queue_t *rq,
- dev_t *devp,
- int flag,
- int sflag,
- cred_t *crp )
- {
- h550port_t *dp;
- minor_t minor_no;
- minorNumInfo_t mInfo;
- short port;
- short ctl;
- int s;
- int error;
-
- chars_rcvd = 0;
- chars_xmt = 0;
-
- if (sflag) /* only a simple stream driver */
- return(ENXIO);
-
- /*
- * Get the Minor device number and figure out the
- * Controller Number.
- */
- minor_no = geteminor(*devp);
- getMinorInfo( minor_no, &mInfo);
- ctl = mInfo.m_ctl;
-
- port = PORT(minor_no);
- if (port > MAX_PORTS) /* fail if bad device # */
- return(ENXIO);
-
- dp = &einfo[ctl].e_ports[port];
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"open: Ctl = %d, Port %d ", ctl, port);
- #endif /* DEBUG2 */
-
- s = LOCK_PORT(dp);
-
- if (!(dp->dp_state & (DP_ISOPEN | DP_WOPEN))) { /* on the 1st open */
-
- ushort_t cflag;
- queue_t *wq = WR(rq);
- cflag = def_stty_ld.st_cflag;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "open: cflag = %x", cflag);
- #endif
-
- dp->dp_rsrv_duration = duart_rsrv_duration;
- dp->dp_state &= ~(DP_TXSTOP | DP_LIT | DP_BLOCK | DP_TX_TXON |
- DP_TX_TXOFF | DP_FLOW | DP_MODEM | DP_EXTCLK);
-
- if ( MODEM(minor_no) ) {
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"open: This is a modem device %d\n",
- minor_no);
- #endif
-
- dp->dp_state |= DP_MODEM;
- cflag &= ~CLOCAL;
- }
-
- if ( FLOW_MODEM(minor_no) ) {
- #ifdef DEBUG2
- cmn_err (CE_NOTE, "This is a Flow Ctl");
- #endif
- dp->dp_state |= DP_FLOW;
- }
-
- comtrol_h550_config(dp, cflag, &def_stty_ld.st_termio);
-
- dp->dp_state |= DP_WOPEN;
-
- if (!comtrol_h550_start_rx(dp) /* wait for carrier */
- && !(dp->dp_cflag & CLOCAL)
- && !(flag & (FNONBLK | FNDELAY)))
- {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "open: wait for DCD carrier");
- #endif
-
- do {
- if (sleep((caddr_t)dp, STIPRI | PCATCH)) {
- dp->dp_state &= ~(DP_WOPEN | DP_ISOPEN);
- h550_zap(dp, HUPCL);
- UNLOCK_PORT(dp,s);
- return(EINTR);
- }
- } while (!(dp->dp_state & DP_DCD));
- }
-
- /*
- * Connect this port to stream
- */
- rq->q_ptr = (caddr_t)dp;
- wq->q_ptr = (caddr_t)dp;
- dp->dp_wq = wq;
- dp->dp_rq = rq;
- dp->dp_state |= DP_ISOPEN;
- dp->dp_state &= ~DP_WOPEN;
- dp->dp_cflag |= CREAD;
-
- h550_rclr(dp); /* discard input */
-
- if (error = strdrv_push(rq, "stty_ld", devp, crp)) {
- dp->dp_state &= ~(DP_ISOPEN | DP_WOPEN);
- dp->dp_rq = NULL;
- dp->dp_wq = NULL;
- h550_zap(dp, HUPCL);
- UNLOCK_PORT(dp,s);
- return(error);
- }
- }
- else { /* This port on this Controller is already opened ! */
- /*
- * you cannot open two streams to the same device. the dp
- * structure can only point to one of them. therefore, you
- * cannot open two different minor devices that are synonyms
- * for the same device. that is, you cannot open both ttym1
- * and ttyd1
- */
-
- if (dp->dp_rq != rq) {
-
- /* fail if already open */
- UNLOCK_PORT(dp,s);
- return(EBUSY);
- }
- }
-
- UNLOCK_PORT(dp,s);
- return(0); /* return successfully */
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ c l o s e *
- **************************************************************************
- *
- * Name: h550_close
- *
- * Description:
- * Closes a port.
- *
- * Returns:
- *
- **************************************************************************
- */
- static int
- h550_close( queue_t *rq,
- int flag,
- cred_t *crp )
- {
- h550port_t *dp;
- int s;
-
- dp = (h550port_t *)rq->q_ptr;
- s = LOCK_PORT(dp);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"close ctrl %d, port %d",
- dp->dp_ctl, dp->dp_index );
- #endif /* DEBUG2 */
-
- if (dp->dp_state & DP_SE_PENDING) {
- dp->dp_state &= ~DP_SE_PENDING;
- str_unbcall(rq);
- }
-
- h550_flushr(dp);
- h550_flushw(dp);
-
- dp->dp_state &= ~(DP_ISOPEN | DP_WOPEN);
- dp->dp_rq = NULL;
- dp->dp_wq = NULL;
-
- h550_zap(dp, dp->dp_cflag & HUPCL);
-
- UNLOCK_PORT(dp,s);
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ r s r v *
- **************************************************************************
- *
- * Name: h550_rsrv
- *
- * Description:
- * Send one or more character up the stream.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_rsrv(queue_t *rq)
- {
- mblk_t *bp;
- h550port_t *dp;
- int s;
-
- dp = (h550port_t *)rq->q_ptr;
- s = LOCK_PORT(dp);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Read service routine");
- #endif /* DEBUG2 */
-
-
- /***** if (!canput(rq->q_next)) { ****** against DDI/DKI ******/
-
- if (!canputnext(rq) ) { /* quit if upstream congested */
- noenable(rq);
- UNLOCK_PORT(dp, s);
- return;
- }
-
- enableok(rq);
- if (dp->dp_state & DP_SE_PENDING) {
- dp->dp_state &= ~DP_SE_PENDING;
- str_unbcall(rq);
- }
-
- /*
- * when we do not have an old buffer to send up, or when we are
- * timing things, send the current buffer
- */
- bp = dp->dp_rbp;
- if (bp && bp->b_wptr > bp->b_rptr
- && (!dp->dp_rmsg || !dp->dp_rsrv_cnt))
- {
- str_conmsg(&dp->dp_rmsg, &dp->dp_rmsge, bp);
- dp->dp_rmsg_len += (bp->b_wptr - bp->b_rptr);
- dp->dp_rbp = NULL;
- }
-
- bp = dp->dp_rmsg;
- if (bp) {
- if (dp->dp_rmsg_len > dp->dp_rbsize)
- dp->dp_rbsize = dp->dp_rmsg_len;
- else
- dp->dp_rbsize = (dp->dp_rmsg_len + dp->dp_rbsize) / 2;
-
- dp->dp_rmsg_len = 0;
- dp->dp_rmsg = NULL;
-
- UNLOCK_PORT(dp, s); /* without too much blocking, */
- putnext(rq, bp); /* send the message */
- s = LOCK_PORT(dp);
- }
-
- comtrol_h550_iflow(dp, SEND_XON, !IGNORE_IXOFF);
-
- /* get a buffer now, rather than waiting for an interrupt */
- if (!dp->dp_rbp)
- (void)h550_getbp(dp, BPRI_LO);
-
- UNLOCK_PORT(dp, s);
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ w p u t *
- **************************************************************************
- *
- * Name: h550_wput
- *
- * Description:
- * Start processing a message ('put' function).
- *
- * Returns:
- *
- **************************************************************************
- */
- static int
- h550_wput( queue_t *wq,
- mblk_t *bp )
- {
- h550port_t *dp;
- int s;
- struct iocblk *iocp;
- unchar c;
-
- dp = (h550port_t *)wq->q_ptr;
- s = LOCK_PORT(dp);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Write put routine");
- #endif /* DEBUG2 */
-
- /* do according to Message type */
- switch (bp->b_datap->db_type) {
-
- case M_FLUSH: /* XXX may not want to restart output since flow
- control may be messed up */
- c = *bp->b_rptr;
- sdrv_flush(wq, bp);
-
- if (c & FLUSHW) {
- h550_flushw(dp);
- dp->dp_state &= ~DP_TXSTOP;
- comtrol_h550_start_tx(dp); /* restart output */
- }
- if (c & FLUSHR)
- h550_flushr(dp);
- break;
-
- case M_DATA:
- case M_DELAY:
- h550_save(dp, wq, bp);
- break;
-
- case M_IOCTL:
- iocp = (struct iocblk *)bp->b_rptr;
-
- switch (iocp->ioc_cmd) {
-
- case TCXONC:
- switch (*(int *)(bp->b_cont->b_rptr)) {
- case 0: /* stop output */
- dp->dp_state |= DP_TXSTOP;
- comtrol_h550_stop_tx(dp);
- break;
- case 1: /* resume output */
- dp->dp_state &= ~DP_TXSTOP;
- comtrol_h550_start_tx(dp);
- break;
- case 2:
- comtrol_h550_iflow(dp, SEND_XOFF, IGNORE_IXOFF);
- break;
- case 3:
- comtrol_h550_iflow(dp, SEND_XON, IGNORE_IXOFF);
- break;
- default:
- iocp->ioc_error = EINVAL;
- break;
- }
-
- iocp->ioc_count = 0;
- bp->b_datap->db_type = M_IOCACK;
- qreply(wq, bp);
- break;
-
- case TCGETA: /* XXXrs - Don't wait until output? */
- ASSERT(iocp->ioc_count == sizeof(struct termio));
- h550_tcgeta(dp->dp_wq,bp, &dp->dp_termio);
- break;
-
- case TCSETA: /* XXXrs - Don't wait until output? */
- ASSERT(iocp->ioc_count == sizeof(struct termio));
- (void)h550_tcset(dp,bp);
- qreply(wq,bp);
- break;
-
- case TCSBRK: /* send BREAK */
- case TCSETAF: /* drain output, flush input, set parameters */
- case TCSETAW: /* drain output, set paramaters */
- h550_save(dp, wq, bp);
- break;
-
- case TCBLKMD:
- dp->dp_iflag |= IBLKMD;
- iocp->ioc_count = 0;
- bp->b_datap->db_type = M_IOCACK;
- qreply(wq, bp);
- break;
-
- default:
- bp->b_datap->db_type = M_IOCNAK;
- qreply(wq, bp);
- break;
- }
- break;
-
- default:
- sdrv_error(wq, bp);
- }
-
- UNLOCK_PORT(dp, s);
- }
-
- /**************************************************************************
- * h 5 5 0 _ h a n d l e _ i n t r *
- **************************************************************************
- *
- * Name: h550_handle_intr
- *
- * Description:
- * Handle interrupt for a given port on a given Controller.
- *
- * Returns: 0 if nothing to do on the specified Ctlr,
- * 1 if something was done
- *
- **************************************************************************
- */
-
- static int
- h550_handle_intr ( int ctl,
- int port )
- {
- h550port_t *dp;
- volatile caddr_t addr;
- uchar_t iir_val, ier_val;
- uchar_t msr_val, lsr_val;
- int i, s;
-
- dp = &einfo[ctl].e_ports[port];
- addr = dp->port_addr;
-
- s = LOCK_PORT(dp);
-
- iir_val = INB(addr+IIR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"intr: Interrupt, Ctl = %d, Port = %d, IIR = %x",
- ctl, port, iir_val);
- #endif /* DEBUG2 */
-
- if (iir_val & INTR_PEND) {
- UNLOCK_PORT(dp, s);
- return(0);
- }
-
- switch(iir_val & 0x0e) {
-
- /* receive character/error interrupt */
- case RDATA_AVAIL:
- case RLINE_STAT:
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "intr: RDATA_AVAIL or RLINE_STAT");
- #endif
-
- SYSINFO.rcvint++;
- h550_rx(dp);
- break;
-
- /* modem status interrupt */
- case MODEM_STAT:
-
-
- /* handle CTS interrupt only if we care, - only if
- * CTS has changed and modem interrupts are enabled
- *
- * If the port's state shows that CTS is active but
- * the MSR doesn't, reset the port's CTS state
- *
- * If the port doesn't show active CTS, but the MSR
- * does, set the port's CTS state to active and
- * restart transmit
- */
- ier_val = INB(addr+IER);
- msr_val = INB(addr+MSR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "intr: Modem_Stat , IER = %x, MSR = %x",
- ier_val, msr_val);
- #endif
-
- if ( (msr_val & DCTS) && (ier_val & EDSSI) ) {
- if ( (dp->dp_state & DP_CTS) &&
- !(msr_val & CTS) ) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "intr: Modem CTS, case 1");
- #endif
-
- SYSINFO.mdmint++;
- dp->dp_state &= ~DP_CTS;
- }
- else if ( !(dp->dp_state & DP_CTS) &&
- (msr_val & CTS) ) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "intr: Modem CTS, case 2");
- #endif
-
- SYSINFO.mdmint++;
- dp->dp_state |= DP_CTS;
- comtrol_h550_start_tx(dp);
- }
- }
-
- /* handle DCD interrupt only if we care - only if
- * DCD has changed and the modem interrupts are
- * enabled
- *
- * If the port's state shows that DCD is active
- * but the MSR doesn't, reset the port's DCD state
- * and kill the port's process
- *
- * If the port's state shows DCD inactive, but the
- * MSR does, set the port's DCD state to active
- * and process the stream waiting for the carrier
- */
- if ( (msr_val & DDCD) && (ier_val & EDSSI) ) {
- if ( (dp->dp_state & DP_DCD) &&
- !(msr_val & DCD) ) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "intr: Modem DCD, case 1");
- #endif
-
- SYSINFO.mdmint++;
- dp->dp_state &= ~DP_DCD;
- h550_coff(dp);
- }
- else if ( !(dp->dp_state & DP_DCD) &&
- (msr_val & DCD) ) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "intr: Modem DCD, case 2");
- #endif
-
- SYSINFO.mdmint++;
- dp->dp_state |= DP_DCD;
- h550_con(dp);
- }
- }
-
- /* handle BREAK interrupt */
- lsr_val = INB(addr+LSR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "intr: Modem_Stat, LSR = %x", lsr_val);
- #endif
-
- if (lsr_val & BI) {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "intr: Modem_Stat, BREAK_ON");
- #endif
- dp->dp_state |= DP_BREAK_ON;
- }
- else {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "intr: Modem_Stat, BREAK_OFF");
- #endif
-
- dp->dp_state &= ~DP_BREAK_ON;
- }
- break;
-
- /* transmit buffer empty interrupt */
- case THREI:
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "intr: THREI (Transmt buf empty)");
- #endif
- SYSINFO.xmtint++;
- h550_tx(dp,0);
- break;
-
- default:
- cmn_err(CE_WARN,"intr: Unknown interrupt type");
- return(0);
- }
-
- UNLOCK_PORT(dp, s);
- return(1);
-
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ p o l l *
- **************************************************************************
- *
- * Name: h550_poll
- *
- * Description:
- * Our interrupt handler. It checks the given Controller
- * number and sees if it is the one needs servicing.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_poll( int ctlr )
- {
- int i;
- edrvinfo_t *einf;
- volatile caddr_t addr;
- uchar_t b;
-
- /* access this controller's data area */
- einf = &einfo[ctlr];
- addr = einf->e_addr[0];
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"poll: Interrupt received, Ctl = %x", ctlr);
- #endif /* DEBUG2 */
-
- /*
- * Look at POLL register and service only those ports with
- * pending interrupts
- */
- b = INB(addr+POLL);
-
- while ( b ) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "poll: Poll value = %x", b);
- #endif
-
- for (i = 0; i < MAX_PORTS; i++)
- if ( b & (1 << i)) {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "poll: port %d interrupted",
- i);
- #endif
- h550_handle_intr(ctlr, i);
- }
- b = INB(addr+POLL);
- }
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ g e t b p *
- **************************************************************************
- *
- * Name: h550_getbp
- *
- * Description:
- * Get a new buffer. This routine should only be called
- * when it is safe from an interrupt.
- *
- * Returns: NULL or the new buffer
- *
- **************************************************************************
- */
-
- static mblk_t*
- h550_getbp( h550port_t *dp,
- uint_t pri )
- {
- mblk_t *bp;
- mblk_t *rbp;
- int size;
- int size0;
- volatile caddr_t addr = dp->port_addr;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Get new buffer routine");
- #endif /* DEBUG2 */
-
- rbp = dp->dp_rbp;
-
- /*
- * if overflowing or current buffer empty, do not
- * need another buffer.
- */
- if ( ( dp->dp_rmsg_len >= MAX_RMSG_LEN ) ||
- ( rbp && rbp->b_rptr >= rbp->b_wptr ) ) {
- cmn_err(CE_NOTE,"don't need another");
- bp = NULL;
- }
- else {
- /*
- * get another buffer, but always keep room to grow.
- * this helps prevent deadlock
- */
- size0 = (dp->dp_rbsize += dp->dp_rbsize / 4);
- if (size0 > MAX_RBUF_LEN)
- size0 = dp->dp_rbsize = MAX_RBUF_LEN;
- else if (size0 < MIN_RMSG_LEN)
- size0 = MIN_RMSG_LEN;
- size = size0;
-
- for ( ; ; ) {
-
- bp = allocb(size, pri);
-
- if (bp)
- break;
- if (pri == BPRI_HI && (size >>= 2) >= MIN_RMSG_LEN)
- continue;
-
- if ( !(dp->dp_state & DP_SE_PENDING) ) {
- bp = str_allocb(size0, dp->dp_rq, BPRI_HI);
- if (!bp)
- dp->dp_state |= DP_SE_PENDING;
- }
- break;
- }
- }
-
- if ( !rbp ) {
- dp->dp_rbp = bp;
- }
- else if ( (bp) || (rbp->b_wptr >= rbp->b_datap->db_lim) ) {
-
- /*
- * we have an old buffer and a new buffer, or old buffer is
- * full
- */
- str_conmsg(&dp->dp_rmsg, &dp->dp_rmsge, rbp);
- dp->dp_rmsg_len += (rbp->b_wptr - rbp->b_rptr);
- dp->dp_rbp = bp;
- }
-
- if ( (dp->dp_rmsg_len >= XOFF_RMSG_LEN) || (!dp->dp_rbp) ) {
- comtrol_h550_iflow ( dp, SEND_XOFF, !IGNORE_IXOFF );
-
- }
-
- return(bp);
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ s l o w r *
- **************************************************************************
- *
- * Name: h550_slowr
- *
- * Description:
- * This routine puts characters in upstream queue.
- * The routine is slow and should be called infrequently.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- h550_slowr( h550port_t *dp,
- uchar_t c )
- {
- mblk_t *bp;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Slow read routine");
- #endif /* DEBUG2 */
-
- if (dp->dp_iflag & IBLKMD) /* this kludge apes the old */
- return; /* block mode hack */
-
- /* get a buffer if we have none */
- if ( !(bp = dp->dp_rbp) &&
- !(bp = h550_getbp(dp, BPRI_HI)) ) {
-
- dp->dp_allocb_fail++;
- return;
- }
-
- /*
- * Put the character into the buffer and
- * send the buffer if it is full
- */
- *bp->b_wptr = c;
- if (++bp->b_wptr >= bp->b_datap->db_lim) {
- (void)h550_getbp(dp, BPRI_LO); /* send buffer when full */
- }
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ r x *
- **************************************************************************
- *
- * Name: h550_rx
- *
- * Description:
- * Interrupt handler for input character/error.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_rx( h550port_t *dp )
- {
- int c;
- uchar_t sr;
- mblk_t *bp;
- volatile caddr_t addr;
-
- addr = dp->port_addr;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"rx: Read routine, dp->dp_state = %x", dp->dp_state);
- #endif /* DEBUG2 */
-
- /* must be open to input */
- if ( (dp->dp_state & (DP_ISOPEN | DP_WOPEN)) != DP_ISOPEN ) {
- if ( !(dp->dp_state & (DP_ISOPEN | DP_WOPEN)) )
- h550_zap(dp, dp->dp_cflag & HUPCL);
- else
- h550_rclr(dp); /* just forget it if partly open */
- return;
- }
-
- /*
- * Must be reading, to read. DCD must be on for modem
- * port to read
- */
- if ( !(dp->dp_cflag & CREAD) ) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "rx: not in READ mode, dp_cflag = %x",
- dp->dp_cflag);
- #endif
-
- h550_rclr(dp);
- return;
- }
-
- /* process all available characters */
- while ( (c = comtrol_h550_getchar(dp) ) != -1 ) {
-
- SYSINFO.rawch++;
- chars_rcvd++;
-
- sr = c >> 8;
- c &= 0xff;
-
- #ifdef DEBUG
- cmn_err(CE_NOTE, "rx: LSR = %x, Received Char: %x [%c]", sr,
- c, (c =='\n' || c == '\r')? '.':c);
- #endif
-
- /* if we get a control-A, debug on this port */
- if ( (kdebug) && (c == CNTRL_A) ) {
- debug("ring");
- continue;
- }
-
- /*
- * XON and XOFF
- * Start/Stop output (if permitted)
- */
- if ( dp->dp_iflag & IXON ) {
-
- uchar_t cs = c;
-
- if (dp->dp_iflag & ISTRIP)
- cs &= 0x7f;
-
- if (dp->dp_state & DP_TXSTOP
- && (cs == dp->dp_cc[VSTART]
- || (dp->dp_iflag & IXANY
- && (cs != dp->dp_cc[VSTOP]
- || dp->dp_line == LDISC0)))) {
-
- dp->dp_state &= ~DP_TXSTOP;
- comtrol_h550_start_tx(dp); /* restart output */
-
- if (cs == dp->dp_cc[VSTART])
- continue;
- }
-
- else if (DP_LIT & dp->dp_state) {
- dp->dp_state &= ~DP_LIT;
- }
-
- else if (cs == dp->dp_cc[VSTOP]) {
-
- dp->dp_state |= DP_TXSTOP;
- comtrol_h550_stop_tx(dp); /* stop output */
- continue;
- }
-
- else if (cs == dp->dp_cc[VSTART]) {
- continue; /* ignore extra control-Qs */
- }
-
- else if (cs == dp->dp_cc[VLNEXT]
- && dp->dp_line != LDISC0) {
- dp->dp_state |= DP_LIT; /* just note escape */
- }
- }
-
- /*
- * we got a Break Interrupt
- */
- if (sr & BI) {
-
- if (dp->dp_iflag & IGNBRK)
- continue; /* ignore it if ok */
-
- if (dp->dp_iflag & BRKINT) {
-
- h550_flushr(dp);
- (void)putctl1(dp->dp_rq->q_next,
- M_FLUSH, FLUSHRW);
- (void)putctl1(dp->dp_rq->q_next,
- M_PCSIG, SIGINT);
- continue;
- }
-
- if (dp->dp_iflag & PARMRK) {
-
- h550_slowr(dp, '\377');
- h550_slowr(dp, '\000');
- }
-
- c = '\000';
- }
-
- else if ( sr & (FE | OE | PE) ) {
-
- if (sr & OE) {
- dp->dp_over++; /* count overrun */
- INB(addr+LSR);
- }
-
- if (dp->dp_iflag & IGNPAR) {
- continue;
- }
-
- else if ( !(dp->dp_iflag & INPCK) ) {
- /* ignore input parity errors if asked */
- }
-
- else if ( sr & (PE | FE) ) {
-
- if (sr & FE)
- dp->dp_fe++;
-
- if (dp->dp_iflag & PARMRK) {
- h550_slowr(dp, '\377');
- h550_slowr(dp, '\000');
- }
- else {
- c = '\000';
- }
- }
-
-
- }
-
- else if (dp->dp_iflag & ISTRIP) {
- c &= 0x7f;
- }
-
- else if (c == '\377' && dp->dp_iflag & PARMRK) {
- h550_slowr(dp, '\377');
- }
-
- if (!(bp = dp->dp_rbp) /* get a buffer if we have none */
- && !(bp = h550_getbp(dp, BPRI_HI))) {
- dp->dp_allocb_fail++;
- continue; /* forget it no buffer available */
- }
-
- *bp->b_wptr = c;
-
- if (++bp->b_wptr >= bp->b_datap->db_lim) {
- (void)h550_getbp(dp, BPRI_LO); /* send when full */
- }
- }
-
-
- if (!dp->dp_rsrv_cnt && dp->dp_rbp) {
-
- if (dp->dp_rsrv_duration <= 0
- || dp->dp_rsrv_duration > HZ / 10) {
-
- if (dp->dp_state & DP_ISOPEN && canenable(dp->dp_rq))
- qenable(dp->dp_rq);
- }
-
- else {
- (void)STREAMS_TIMEOUT(h550_rsrv_timer,
- (caddr_t)dp, dp->dp_rsrv_duration);
- dp->dp_rsrv_cnt = MAX_RSRV_CNT;
- }
- }
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ c o n *
- **************************************************************************
- *
- * Name: h550_con
- *
- * Description:
- * Process Carrier_On Interrupt for a given port.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- h550_con( h550port_t *dp )
- {
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Carrier ON routine");
- #endif /* DEBUG2 */
-
- if (dp->dp_state & DP_WOPEN)
- wakeup((caddr_t)dp); /* awaken open() requests */
- }
-
-
-
- /**************************************************************************
- * h 5 5 0 _ c o f f *
- **************************************************************************
- *
- * Name: h550_coff
- *
- * Description:
- * Process Carrier_Off Interrupt for a given port.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- h550_coff( h550port_t *dp )
- {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"Carrier OFF routine");
- #endif /* DEBUG2 */
-
- if ( !(dp->dp_cflag & CLOCAL) && /* worry only for an open modem */
- (dp->dp_state & DP_ISOPEN) ) {
-
- h550_zap(dp, HUPCL); /* kill the modem */
- flushq(dp->dp_wq, FLUSHDATA);
- (void)putctl1(dp->dp_rq->q_next, M_FLUSH, FLUSHW);
- (void)putctl(dp->dp_rq->q_next, M_HANGUP);
- }
- }
-
-
- /**************************************************************************
- * h 5 5 0 _ t x *
- **************************************************************************
- *
- * Name: h550_tx
- *
- * Description:
- * Outputs to a port.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- h550_tx( h550port_t *dp,
- int prime )
- {
- uchar_t c;
- mblk_t *wbp;
- int local_fifo_size, count;
- volatile caddr_t addr;
-
- addr = dp->port_addr;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"tx: Output routine");
- #endif /* DEBUG2 */
-
- if (!comtrol_h550_txrdy(dp))
- return;
-
- local_fifo_size = count = 1;
-
- /* send all we can */
- while ( comtrol_h550_txrdy(dp) ) {
-
- if (!(dp->dp_state & DP_ISOPEN)
- || dp->dp_state & (DP_BREAK | DP_BREAK_QUIET)
- || dp->dp_state & (DP_TXSTOP | DP_TIMEOUT)
- && !(dp->dp_state & (DP_TX_TXON | DP_TX_TXOFF))) {
-
- comtrol_h550_stop_tx(dp);
- return;
- }
-
- SYSINFO.outch++;
-
- /* send XON or XOFF */
- if (dp->dp_state & DP_TX_TXON) {
-
- if ( (dp->dp_state & DP_FLOW) &&
- !(dp->dp_state & DP_CTS) ) {
-
- comtrol_h550_stop_tx(dp);
- return;
- }
-
- c = dp->dp_cc[VSTART];
- dp->dp_state &= ~(DP_TX_TXON | DP_TX_TXOFF | DP_BLOCK);
- }
-
- else if (dp->dp_state & DP_TX_TXOFF) {
-
- if ( (dp->dp_state & DP_FLOW) &&
- !(dp->dp_state & DP_CTS) ) {
-
- comtrol_h550_stop_tx(dp);
- return;
- }
-
- c = dp->dp_cc[VSTOP];
- dp->dp_state &= ~DP_TX_TXOFF;
- dp->dp_state |= DP_BLOCK;
-
- }
-
- else {
- if (!(wbp = dp->dp_wbp)) { /* get another msg */
- wbp = getq(dp->dp_wq);
- if (!wbp) {
- comtrol_h550_stop_tx(dp);
- return;
- }
-
- switch (wbp->b_datap->db_type) {
-
- case M_DATA:
- dp->dp_wbp = wbp;
- break;
-
- /* must wait until output drained */
- case M_DELAY: /* start output delay */
-
- if (count == local_fifo_size) {
- dp->dp_state |= DP_TIMEOUT;
- dp->dp_tid =
- STREAMS_TIMEOUT(h550_delay,
- (caddr_t)dp,
- *(int *)wbp->b_rptr);
- freemsg(wbp);
- continue;
- }
- else {
- putbq(dp->dp_wq, wbp);
- return;
- }
-
- /* must wait until output drained */
- case M_IOCTL:
- if (count == local_fifo_size) {
- h550_i_ioctl(dp, wbp);
- continue;
- }
- else {
- putbq(dp->dp_wq, wbp);
- return;
- }
-
- default:
- panic("bad uart msg");
- }
- }
-
- if ( (dp->dp_state & DP_FLOW) &&
- !(dp->dp_state & DP_CTS) ) {
- comtrol_h550_stop_tx(dp);
- return;
- }
-
- if (wbp->b_rptr >= wbp->b_wptr) {
- dp->dp_wbp = rmvb(wbp, wbp);
- freeb(wbp);
- continue;
- }
-
- c = *wbp->b_rptr++;
- }
-
- #ifdef DEBUG
- cmn_err(CE_NOTE, "tx: Sending char: %x [%c]", c,
- (c =='\n' || c == '\r')? '.':c);
- #endif
-
- comtrol_h550_putchar(dp, c);
- chars_xmt++;
- count--;
- }
-
- /*
- * If the queue is now empty, put an empty data block on it
- * to prevent a close from finishing prematurely.
- */
- if ( (!dp->dp_wq->q_first) &&
- (dp->dp_wbp) &&
- (wbp = allocb(0, BPRI_HI)) ) {
- putbq(dp->dp_wq, wbp);
- }
-
- }
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ t x r d y *
- **************************************************************************
- *
- * Name: comtrol_h550_txrdy
- *
- * Description:
- * Determine if a given port is ready to transmit a
- * character or not.
- *
- * Returns: 0 = Not Ready
- *
- **************************************************************************
- */
-
- static int
- comtrol_h550_txrdy( h550port_t *dp )
- {
- volatile caddr_t addr;
- uchar_t b;
- addr = dp->port_addr;
-
-
- b = INB(addr+LSR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"txrdy: Tx Ready routine, LSR = %x, LSR & THRE = %x",
- b, b & THRE );
- #endif /* DEBUG2 */
-
- return( b & THRE);
- }
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ p u t c h a r *
- **************************************************************************
- *
- * Name: comtrol_h550_putchar
- *
- * Description:
- * Transmit a character. The routine 'comtrol_h550_txrdy'
- * must be called first to make sure the port is ready.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- comtrol_h550_putchar(h550port_t *dp, uchar_t c)
- {
- volatile caddr_t addr;
-
- addr = dp->port_addr;
-
- #ifdef DEBUG
- cmn_err(CE_NOTE,"***-> putchar: Outputing: %x [%c]", c,
- (c =='\n' || c == '\r')? '.':c);
- #endif /* DEBUG2 */
-
- OUTB(addr+THR,c);
- }
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ g e t c h a r *
- **************************************************************************
- *
- * Name: comtrol_h550_getchar
- *
- * Description:
- * Get a character from a port and append status
- * to the data.
- *
- * Returns: -1 if no character received.
- *
- **************************************************************************
- */
-
- static int
- comtrol_h550_getchar( h550port_t *dp )
- {
- volatile caddr_t addr;
- uchar_t lsr_val;
- uchar_t rbr;
-
- addr = dp->port_addr;
- lsr_val = INB(addr+LSR);
-
-
- if (lsr_val & DR) {
- /* read possible error status */
- if (lsr_val &= (FE | OE | PE) ) {
- #ifdef DEBUG2
- if ( lsr_val & FE )
- cmn_err(CE_WARN, "!Framing error on serial port %d",
- dp->dp_index);
-
- if ( lsr_val & OE )
- cmn_err(CE_WARN, "!Overrun error on serial port %d",
- dp->dp_index);
-
- if ( lsr_val & PE )
- cmn_err(CE_WARN, "!Parity error on serial port %d",
- dp->dp_index);
- #endif /* DEBUG2 */
- }
-
- if (dp->dp_state & DP_BREAK_ON)
- lsr_val |= BI;
-
- /*
- * return Line Status Register value (as upper 8 bits)
- * and received character
- */
- rbr = INB(addr+RBR);
- #ifdef DEBUG
- cmn_err(CE_NOTE,
- "***-> getchar: LSR = %x, Received Char: %x [%c]", lsr_val,
- rbr, (rbr =='\n' || rbr == '\r')? '.':rbr);
- #endif
-
- return ( lsr_val << 8 | rbr );
- }
- else
- return(-1);
- }
-
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ s t o p _ t x
- **************************************************************************
- *
- * Name: comtrol_h550_stop_tx
- *
- * Description:
- * Stop transmission on a port.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- comtrol_h550_stop_tx(h550port_t *dp)
- {
- volatile caddr_t addr;
- int s;
- uchar_t b;
-
- addr = dp->port_addr;
- s = LOCK_PORT(dp);
-
-
- b = INB(addr+IER);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "stop_tx: Stop transmit routine, IER before: %x", b);
- #endif /* DEBUG2 */
-
- b &= ~ETBEI;
- OUTB(addr+IER, b);
-
- UNLOCK_PORT(dp,s);
-
- }
-
-
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ s t a r t _ t x *
- **************************************************************************
- *
- * Name: comtrol_h550_start_tx
- *
- * Description:
- * Enable port for transmission (start transmission).
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- comtrol_h550_start_tx( h550port_t *dp )
- {
- volatile caddr_t addr;
- uchar_t b;
-
- addr = dp->port_addr;
-
- /* if the boards outputs are not enabled, enable them */
- b = INB(addr+MCR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_tx: MCR = %x", b);
- #endif
-
- if ( !(b & OUT2) ) {
- OUTB( (addr+MCR), b | OUT2);
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_tx: Enabling Board Output-2, MCR=%x",
- b | OUT2);
- #endif
- }
-
- /*
- * if transmit interrupts are not enabled, enable them
- * and transmit one character to prime the pump
- */
- b = INB(addr+IER);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_tx: board IER = %x", b);
- #endif
-
- if ( !( b & ETBEI) ) {
- OUTB((addr+IER), b | ETBEI);
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_tx: Enablin Transmit Intr, IER = %x",
- b | ETBEI );
- #endif
- h550_tx(dp,1); /* send something (1 char) */
- }
- }
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ s t o p _ t x *
- **************************************************************************
- *
- * Name: comtrol_h550_stop_tx
- *
- * Description:
- * Stop the receive process.
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- comtrol_h550_stop_rx( h550port_t *dp,
- int hup )
- {
- volatile caddr_t addr;
- int s;
- uchar_t b;
-
- addr = dp->port_addr;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"stop_rx: Stop receive routine");
- #endif /* DEBUG2 */
-
- /*
- * deassert RTS, DTR if hup != 0
- * deassert output handshake signals on tty port
- */
- if (hup) {
- s = LOCK_PORT(dp);
- /*** changed the following line
- OUTB(addr+MCR, INB(addr+MCR) & ~(DTR & RTS));
- ****/
- b = INB(addr+MCR);
- b &= ~(DTR | RTS);
- OUTB(addr+MCR, b);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "stop_rx: hup, set MCR to: %x", b);
- #endif
-
- UNLOCK_PORT(dp,s);
- }
-
- /*
- * disable interrupt to the board
- */
- s = LOCK_PORT(dp);
- b = INB(addr+MCR);
- b &= ~OUT2;
- OUTB(addr+MCR, b);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "stop_rx: Disabling Int, MCR = %x", b);
- #endif
-
- UNLOCK_PORT(dp,s);
- }
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ s t a r t _ r x *
- **************************************************************************
- *
- * Name: comtrol_h550_start_rx
- *
- * Description:
- * Start the receive process.
- *
- * Returns: !0 if Carrier detected
- *
- **************************************************************************
- */
- static int
- comtrol_h550_start_rx( h550port_t *dp )
- {
- volatile caddr_t addr;
-
- uchar_t iir_val, msr_val;
- uchar_t mcr_val, ier_val;
- uchar_t temp;
-
- addr = dp->port_addr;
-
- mcr_val = INB(addr+MCR);
- ier_val = INB(addr+IER);
-
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"start_rx: MCR = %x, IER = %x", mcr_val, ier_val);
- #endif /* DEBUG2 */
-
-
- /* assert DTR and RTS and enable board outputs */
- mcr_val |= (DTR | RTS | OUT2);
- OUTB(addr+MCR, mcr_val);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: set DTR, RTS and OUT2, new MCR = %x",
- mcr_val );
- #endif
-
- /* watch carrier-detect only if this is an open modem port */
- if ( !(dp->dp_cflag & CLOCAL) &&
- (dp->dp_state & (DP_ISOPEN | DP_WOPEN)) ) {
-
- if (dp->dp_state & DP_FLOW) {
- ier_val |= (ERBFI | ELSI | EDSSI);
- OUTB(addr+IER, ier_val);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "start_rx: set ERBFI, ELSI, EDSSI, new IER = %x",
- ier_val);
- #endif
- }
- }
-
- else {
- ier_val |= (ERBFI | ELSI);
- OUTB(addr+IER, ier_val);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "start_rx: set ERBFI, ELSI, new IER = %x", ier_val);
- #endif
-
- OUTB(addr+IER, ier_val | (ERBFI | ELSI));
- }
-
- /* if now enabling input and there are no pending
- * receive interrupts, gobble old stuff
- */
- iir_val = INB(addr+IIR);
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: IIR = %x", iir_val );
- #endif
-
- if (!(iir_val & (RDATA_AVAIL | RLINE_STAT))) {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: clearing old data");
- #endif
- h550_rclr(dp);
- }
-
- temp = INB(addr+LSR) & BI;
- if (temp) { /* receiving break ? */
- dp->dp_state |= DP_BREAK_ON;
- }
-
- else {
- dp->dp_state &= ~DP_BREAK_ON;
- }
-
- msr_val = INB(addr+MSR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: MSR = %x", msr_val);
- #endif
-
- if (msr_val & CTS) {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: CTS on");
- #endif
- dp->dp_state |= DP_CTS;
- }
- else {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: CTS off");
- #endif
- dp->dp_state &= ~DP_CTS;
- }
-
- if (msr_val & DCD) {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: DCD on");
- #endif
-
- dp->dp_state |= DP_DCD;
- }
- else {
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "start_rx: DCD off");
- #endif
-
- dp->dp_state &= ~DP_DCD;
- }
-
- return(dp->dp_state & DP_DCD);
-
- }
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ c o n f i g *
- **************************************************************************
- *
- * Name: comtrol_h550_config
- *
- * Description:
- * Port configuration.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- comtrol_h550_config(h550port_t *dp,
- ushort_t cflag,
- struct termio *tp )
- {
- volatile caddr_t addr;
- ushort_t temp, temp_lcr = 0;
- ushort_t delta_cflag;
- ushort_t time_constant;
- uchar_t b;
- addr = dp->port_addr;
-
- delta_cflag = (cflag ^ dp->dp_cflag)
- & (CBAUD | CLOCAL | CSIZE | CSTOPB | PARENB | PARODD);
-
- if (tp)
- dp->dp_termio = *tp;
-
- dp->dp_cflag = cflag;
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"config port routine");
- #endif /* DEBUG2 */
-
- /*
- * always configures during open in case the last process set up
- * the port to use the external clock and did not set it back to use
- * the internal BRG
- */
- if (delta_cflag || !(dp->dp_state & DP_ISOPEN)) {
-
- if ((cflag & CBAUD) == B0) { /* hang up line if asked */
- h550_coff(dp);
- h550_zap(dp, HUPCL);
- }
-
- else {
- /* reset the XMT and RCV FIFO's */
- /***** changed as below
- OUTB(addr+FCR, INB(addr+FCR) & (RFIFO_RST|TFIFO_RST));
- *******/
- b = 0;
- b |= (RFIFO_RST|TFIFO_RST);
- OUTB(addr+FCR, b);
-
- /* set number of data bits */
- switch (cflag & CSIZE) {
-
- case CS5:
- temp_lcr &= ~(WLS0 | WLS1);
- break;
-
- case CS6:
- temp_lcr |= WLS0;
- temp_lcr &= ~(WLS1);
- break;
-
- case CS7:
- temp_lcr &= ~(WLS0);
- temp_lcr |= WLS1;
- break;
-
- case CS8:
- temp_lcr |= (WLS0 | WLS1);
- break;
- }
-
-
- /* set number of stop bits */
- temp = cflag & CSTOPB;
- if (cflag & CSTOPB)
- temp_lcr |= STB;
- else
- temp_lcr &= ~(STB);
-
- /* set parity and type (odd/even) */
- if (cflag & PARENB) {
- temp_lcr |= PEN;
- if (!(cflag & PARODD))
- temp_lcr |= EPS;
- }
-
-
- /*
- * set baud rate divisor registers based
- * on value in baud rate table
- *
- * First, enable read/write of baud rate
- * divisor latches then write out LS byte,
- * write out MS byte,
- * then disable read/write of baud rate
- * divisor latches
- */
-
- OUTB(addr+LCR,INB(addr+LCR) | DLAB);
- OUTB(addr+DLL,h550_baudtbl[cflag&CBAUD]&0xff);
- OUTB(addr+DLM,h550_baudtbl[cflag&CBAUD] >> 8);
- OUTB(addr+LCR,INB(addr+LCR) & ~(DLAB));
-
- /*
- * output Line Control settings to uart's
- * Line Control Register
- */
- OUTB(addr+LCR, INB(addr+LCR) | temp_lcr);
-
- /*
- * set temp to value of Interrupt Enable
- * register with the first four
- * bits set to zero (i.e. disabled)
- */
- temp = INB(addr+IER);
- temp &= ~(ELSI|ERBFI|ETBEI|EDSSI);
-
- /* output this info to the IER */
- OUTB(addr+IER,temp);
-
- (void)comtrol_h550_start_rx(dp);
- }
- }
- }
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ i f l o w *
- **************************************************************************
- *
- * Name: comtrol_h550_iflow
- *
- * Description:
- * Flow control on a port.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- static void
- comtrol_h550_iflow( h550port_t *dp,
- int send_xon,
- int ignore_ixoff )
- {
- volatile caddr_t addr;
- uchar_t mcr_val;
-
-
- addr = dp->port_addr;
- mcr_val = INB(addr+MCR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,"iflow: MCR = %x", mcr_val);
- #endif /* DEBUG2 */
-
-
- /* if hardware flow control */
- if (dp->dp_state & DP_FLOW) {
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE, "iflow: DP_FLOW");
- #endif
- if (send_xon && !(mcr_val & RTS)) {
- OUTB(addr+MCR, mcr_val |= RTS);
- }
-
- else if (!send_xon && (mcr_val & RTS)) {
- OUTB(addr+MCR, mcr_val &= ~(RTS));
- }
- }
-
- if (!ignore_ixoff && !(dp->dp_iflag & IXOFF))
- return;
-
- else {
- if (send_xon && dp->dp_state & DP_BLOCK) {
- dp->dp_state |= DP_TX_TXON;
- comtrol_h550_start_tx(dp);
- }
- else if (!send_xon && !(dp->dp_state & DP_BLOCK)) {
- dp->dp_state |= DP_TX_TXOFF;
- dp->dp_state &= ~DP_TX_TXON;
- comtrol_h550_start_tx(dp);
- }
- }
- }
-
-
-
- /**************************************************************************
- * c o m t r o l _ h 5 5 0 _ b r e a k *
- **************************************************************************
- *
- * Name: comtrol_h550_break
- *
- * Description:
- * process Break for a port
- *
- * Returns:
- *
- **************************************************************************
- */
- static void
- comtrol_h550_break( h550port_t *dp,
- int start_break )
- {
- volatile caddr_t addr;
- uchar_t lcr_val;
-
- addr = dp->port_addr;
- lcr_val = INB(addr+LCR);
-
- #ifdef DEBUG2
- cmn_err(CE_NOTE,
- "break: LCR = %x, start_break = %x", lcr_val, start_break);
- #endif /* DEBUG2 */
-
- if (start_break)
- lcr_val |= BRK;
- else lcr_val &= ~BRK;
-
- OUTB(addr+LCR, lcr_val);
- }
-
-
-
- /**************************************************************************
- * S h o w P o r t I n f o *
- **************************************************************************
- *
- * Name: ShowPortInfo
- *
- * Description:
- * Shows Port info for a given port.
- *
- * Returns:
- *
- **************************************************************************
- */
- void
- ShowPortInfo( ushort_t ctl,
- h550port_t *dp )
- {
-
- caddr_t addr;
-
- addr = dp->port_addr;
-
- cmn_err(CE_NOTE,"%d[%d]:\tRBR\tIER\tIIR\tLCR\tMCR\tLSR\tMSR",
- ctl, dp->dp_index);
-
- cmn_err(CE_NOTE,"\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x\t0x%x",
- INB(addr+RBR),
- INB(addr+IER),
- INB(addr+IIR),
- INB(addr+LCR),
- INB(addr+MCR),
- INB(addr+LSR),
- INB(addr+MSR) );
-
- }
-
-
-
- /**************************************************************************
- * g e t M i n o r I n f o *
- **************************************************************************
- *
- * Name: getMinorInfo
- *
- * Description:
- * For a given device Minor number, this routine
- * figures out the Controller and Port number and
- * sees if the port is used as a Modem or a Flow
- * Control.
- *
- * Returns:
- *
- **************************************************************************
- */
-
- void
- getMinorInfo ( minor_t minor_no,
- minorNumInfo_t *minfo )
- {
- short ctl;
-
- bzero(minfo, sizeof(minorNumInfo_t) );
- if ( minor_no <= 7 ) {
- minfo->m_port = minor_no;
- minfo->m_ctl = 0;
- return;
- }
-
- minfo->m_port = minor_no % 8;
- ctl = minor_no / 8;
-
- if ( ctl >= 4 )
- ctl = ctl % 4;
-
- minfo->m_ctl = ctl;
-
- if ( (minor_no >= 32) && (minor_no <= 63) ) {
- minfo->m_modem = 1;
- }
-
- if ( (minor_no >= 64) && (minor_no <= 95) ) {
- minfo->m_flow = 1;
- }
- }
-
-